#!/usr/bin/python
################################################################################
# 
#  Title:         Data Generation script for Simmode
#
#  Author:        LTE eNB Integration & Verification 
#
#  Description:   Python script that handles the data generation for simmode
#  
#  Copyright 2008-2012 Nokia Siemens Networks Oyj
#
################################################################################


#################################################
# Import libraries and Modules
#################################################
# Python Libraries and Modules
import os
import sys
import re
import getopt
import csv
import random
import subprocess
from collections import defaultdict
import datetime
import time

#############################################
# datagen4simmode.py usage
#############################################
def usage():
   print ""
   print " Usage: datagen4simmode.py [-h] [-i ue_ids] <datagen_direction> <datagen_config_csv>"
   print ""
   print " Input arguments:"
   print "   datagen_direction    : data generation direction."
   print "                          select one of following options: 'UL_server', 'UL_client', 'DL_server' and 'DL_client'"
   print "   datagen_config_csv   : data generation configuration CSV file"
   print ""   
   print " Options:"
   print "   -h                  : print this help message and exit"
   print "   -t time_interval    : time interval between UE IDs data generation"
   print "   -r random_samples   : selects randomSamples values from UE ID list, from configuration file or from option -i ue_ids"
   print "   -i ue_ids           : selects the UE IDs only from ue_ids list (e.g. 1,3,5,7-15)"
   print "                         the chars ',' separates Ids and '-' defines ranges of Ids"
   print "                         if option -i is not used the UE IDs will be read from datagen_config_csv file"
   print ""
   print " Examples:"
   print "   datagen4simmode.py UL_server iperf_udp_template.csv"
   print "      - gets the UL Server data generation CSV parameters for all UEids listed in CSV file and starts iperf udp client processes"
   print "   datagen4simmode.py -i 1001-1005 UL_server iperf_udp_template.csv"
   print "      - gets the UL Server data generation CSV parameters for UEids from 1001 to 1005 and starts iperf udp client processes"
   print "   datagen4simmode.py -i 1001-1005 UL_client iperf_udp_template.csv"
   print "      - gets the UL Client data generation CSV parameters for UEids from 1001 to 1005 and starts iperf udp client processes"
   print "   datagen4simmode.py UL_client ping_template.csv"
   print "      - gets the ping data generation CSV parameters for all UEids listed in CSV file and starts ping processes"
   print "   datagen4simmode.py -r 10 DL_client ping_template.csv"
   print "      - gets the ping data generation CSV parameters for all UEids listed in CSV file, selects 10 random UEIds and starts ping processes"
   print "   datagen4simmode.py -i 1001-1050,2001-2050 -r 10 DL_client ping_template.csv"
   print "      - gets the ping data generation CSV parameters for UEids in range 1001-1050 & 2001-2050, selects 10 random UEIds and starts ping processes"
   print ""
   print ""


##########################################################################################
# M A I N
##########################################################################################

#--------------------------------------------------------------------------------
# read command line arguments 
#--------------------------------------------------------------------------------
try:
    opts, args = getopt.getopt(sys.argv[1:], "hi:r:t:", ["help", "ue_ids=","randomSamples="])
    if len(args) < 2:
        usage()
        sys.exit()
    else:
        datagen_direction = args[0]
        if datagen_direction != 'UL_server' and datagen_direction != 'UL_client' and datagen_direction != 'DL_server' and datagen_direction != 'DL_client':
            raise getopt.GetoptError("invalid input arguments: unknown datagen_direction='%s'"%datagen_direction)
        datagen_config_csv = args[1]    
        try: 
            inFile = open(datagen_config_csv,'rb')
        except IOError as str_e:
            raise getopt.GetoptError("invalid input arguments: %s"%str_e)
except getopt.GetoptError, err:
    # print help information and exit:
    print str("invalid options arguments: %s"%err) # will print something like "option -a not recognized"
    usage()
    sys.exit(2)


#--------------------------------------------------------------------------------
# default parameters values
#--------------------------------------------------------------------------------
ue_list = []
csvDelimiter = ";"
ueNumberOfSamples = None
ueSampleValues = None
client_useXterm = False
server_useXterm = False
ueTimeInterval = None

cellid_col = 0
ueid_col = 1
drb_col = 2
ueip_col = 3
cnip_col = 4
dlapp_col = 5
dlprotocol_col = 6
dlport_col = 7
dlnumstreams_col = 8
dltput_col = 9
dlpktsize_col = 10
dltime_col = 11
ulapp_col = 12
ulprotocol_col = 13
ulport_col = 14
ulnumstreams_col = 15
ultput_col = 16
ulpktsize_col = 17
ultime_col = 18

#--------------------------------------------------------------------------------
# parse command line arguments
#--------------------------------------------------------------------------------
for opt, optValue in opts:
    if opt in ("-h", "--help"):
        usage()
        sys.exit()
    elif opt in ("-i", "--ue_ids"):
        ue_ids = optValue
        sys.__stdout__.write("parsing ue_ids option with %s "%ue_ids.split(','))
        for idOpt in ue_ids.split(','):
            if idOpt.find('-') > 0: ue_list += range(int(idOpt.split('-')[0]),int(idOpt.split('-')[1])+1)
            else: ue_list.append(int(idOpt))
            sys.__stdout__.write('.')
        print("done!")
    elif opt in ("-r", "--random_samples"):
        ueNumberOfSamples = int(optValue)
    elif opt in ("-t", "--time_interval"):
        ueTimeInterval = float(optValue)
    else:
        assert False, "unhandled option '%s'"%opt
# ...

#--------------------------------------------------------------------------------
# read datagen CSV file and defines UE ID list to be used for data generation
#--------------------------------------------------------------------------------
datagenCsvData = csv.reader(inFile, delimiter=str(csvDelimiter))
datagenDict = defaultdict(lambda: defaultdict(defaultdict))
rownum = 0
for row in datagenCsvData:
    if rownum != 0:
        cellid=int(row[cellid_col].lower().strip('cell'))
        ueid=int(row[ueid_col].lower().strip('ue'))
        drb=int(row[drb_col])
        ueip=row[ueip_col]
        cnip=row[cnip_col]
        dlapp=row[dlapp_col]
        dlprotocol=row[dlprotocol_col]
        dlport=row[dlport_col]
        dlnumstreams=row[dlnumstreams_col]
        dltput=row[dltput_col]
        dlpktsize=row[dlpktsize_col]
        dltime=row[dltime_col]
        ulapp=row[ulapp_col]
        ulprotocol=row[ulprotocol_col]
        ulport=row[ulport_col]
        ulnumstreams=row[ulnumstreams_col]
        ultput=row[ultput_col]
        ulpktsize=row[ulpktsize_col]
        ultime=row[ultime_col]
        #print "cellid=%s ueid=%s drbid=%s cnip=%s ueip=%s"%(cellid,ueid,drb,cnip,ueip)
        datagenDict[cellid][ueid][drb] = [ueip,cnip,dlapp,dlprotocol,dlport,dlnumstreams,dltput,dlpktsize,dltime,ulapp,ulprotocol,ulport,ulnumstreams,ultput,ulpktsize,ultime]
    rownum += 1
#print("DEBUG: datagenDict = %s"%datagenDict)

if len(ue_list) == 0:
    for cellid in datagenDict:
        print "datagenDict[cellid=%s] has %s UEs "%(cellid,len(datagenDict[cellid]))
        for ueid in datagenDict[cellid]:
            ue_list.append(ueid)

print("DEBUG: input ue_list = %s"%ue_list)

try:
    if ueNumberOfSamples != None:
        print("selecting '%s' random samples from UE ID list... "%ueNumberOfSamples)
        ueSampleValues = random.sample(ue_list,ueNumberOfSamples)
        #sys.__stdout__.write("ue_ids sample values = %s\n"%ueSampleValues)
        ue_list = ueSampleValues
except Exception as str_e:
    assert False, "error: %s"%str_e

print("DEBUG: final ue_list = %s"%ue_list)

#--------------------------------------------------------------------------------
# starts data generation according to configuration CSV file and UE ID list
#--------------------------------------------------------------------------------
print("Start data generation...")
uePing=0
ueIperfclient_udp=0
ueIperfserver_udp=0
ueIperfclient_tcp=0
ueIperfserver_tcp=0
cnPing=0
cnIperfclient_udp=0
cnIperfserver_udp=0
cnIperfclient_tcp=0
cnIperfserver_tcp=0
offset=3
pwd="."
for ueid in ue_list:
    cellid=ueid/1000
    drbnum=len(datagenDict[cellid][ueid])
    #print("\n...ueid %s is on cell=%s and contains drbnum=%s"%(ueid,cellid,drbnum))
    #print("  datagenInfo: %s"%datagenDict[cellid][ueid])
    if datagenDict[cellid][ueid] == {}:
        assert False, "datagen information for ueid=%s not found in datagenDict!!!!"%ueid
    for drbid in datagenDict[cellid][ueid]:
        ueip=datagenDict[cellid][ueid][drbid][ueip_col-offset]
        cnip=datagenDict[cellid][ueid][drbid][cnip_col-offset]
        dlapp=datagenDict[cellid][ueid][drbid][dlapp_col-offset]
        dlprotocol=datagenDict[cellid][ueid][drbid][dlprotocol_col-offset]
        dlport=datagenDict[cellid][ueid][drbid][dlport_col-offset]
        dlnumstreams=datagenDict[cellid][ueid][drbid][dlnumstreams_col-offset]
        dltcpws='2.0M'
        #dltcpws='64.0K'
        dltput=datagenDict[cellid][ueid][drbid][dltput_col-offset]
        dlpktsize=datagenDict[cellid][ueid][drbid][dlpktsize_col-offset]
        dltime=datagenDict[cellid][ueid][drbid][dltime_col-offset]
        ulapp=datagenDict[cellid][ueid][drbid][ulapp_col-offset]
        ulprotocol=datagenDict[cellid][ueid][drbid][ulprotocol_col-offset]
        ulport=datagenDict[cellid][ueid][drbid][ulport_col-offset]
        ulnumstreams=datagenDict[cellid][ueid][drbid][ulnumstreams_col-offset]
        ultcpws='2.0M'
        #ultcpws='64.0K'
        ultput=datagenDict[cellid][ueid][drbid][ultput_col-offset]
        ulpktsize=datagenDict[cellid][ueid][drbid][ulpktsize_col-offset]
        ultime=datagenDict[cellid][ueid][drbid][ultime_col-offset]
        #print("  ...drbid %s ueip=%s cnip=%s dlapp=%s dlprotocol=%s dlport=%s dltput=%s dlpktsize=%s dltime=%s ulapp=%s ulprotocol=%s ulport=%s ultput=%s ulpktsize=%s ultime=%s"%(drbid,ueip,cnip,dlapp,dlprotocol,dlport,dltput,dlpktsize,dltime,ulapp,ulprotocol,ulport,ultput,ulpktsize,ultime))
        # Get current date and timestamp
        now = datetime.datetime.now()
        starttime = "%2.2d%2.2d%2.2d_%2.2d%2.2d%2.2d"%(now.year,now.month,now.day,now.hour,now.minute,now.second)
        # UPLINK
        if ulapp=='iperf':
            # UL iperf CLIENT
            if datagen_direction == 'UL_client':
                if ulprotocol == "UDP":
                    print("Sending %s traffic for %s (DRB%s) on port %s - from %s to %s" % (ulprotocol,ueid,drbid,ulport,ueip,cnip))
                    logfile="%s/data_logs/client/%s_iperf_UL_client_%s_DRB%s.csv"%(pwd,starttime,ueid,drbid)
                    if client_useXterm: cmd="xterm -e \"iperf -c %s -u -P %s -i 1 -p %s -f k -l %s -b %s -t %s -T 1 | tee -a %s\" &" % (cnip,ulnumstreams,ulport,ulpktsize,ultput,ultime,logfile)
                    else: cmd="iperf -c %s -u -P %s -i 1 -p %s -f k -l %s -b %s -t %s -T 1 > %s &" % (cnip,ulnumstreams,ulport,ulpktsize,ultput,ultime,logfile)
                    #print(cmd);
                    os.system(cmd)
                    ueIperfclient_udp += 1
                elif ulprotocol == "TCP":
                    print("Sending %s traffic for %s (DRB%s) on port %s - from %s to %s" % (ulprotocol,ueid,drbid,ulport,ueip,cnip))
                    logfile="%s/data_logs/client/%s_iperf_UL_client_%s_DRB%s.csv"%(pwd,starttime,ueid,drbid)
                    if client_useXterm: cmd="xterm -e \"iperf -c %s -w %s -P %s -i 1 -p %s -l %s -t %s | tee -a %s\" &" % (cnip,ultcpws,ulnumstreams,ulport,ulpktsize,ultime,logfile)
                    else: cmd="iperf -c %s -w %s -P %s -i 1 -p %s -l %s -t %s > %s &" % (cnip,ultcpws,ulnumstreams,ulport,ulpktsize,ultime,logfile)
                    #print(cmd);
                    os.system(cmd)
                    ueIperfclient_tcp += 1
                else:
                    print("unknown '%s' protocol for iperf. Please use UL 'UDP' or 'TCP' protocol for %s (DRB%s)"%(ulprotocol,ueid,drbid))
            
            # UL iperf SERVER
            if datagen_direction == 'UL_server':
                if ulprotocol == "UDP":
                    print("Receiving %s traffic for %s (DRB%s) on port %s - from %s to %s" % (ulprotocol,ueid,drbid,ulport,ueip,cnip))
                    logfile="%s/data_logs/server/%s_iperf_UL_server_%s_DRB%s.csv"%(pwd,starttime,ueid,drbid)
                    cmd="touch %s"%logfile
                    os.system(cmd)
                    cmd="echo \"timestamp,src ip,src port,dest ip,dest port,Id,interval [sec],transfered [bytes],bandwidth [bps],jitter [ms],lost [pkt],total [pkt],lost [%%],out-of-order\" > %s"%logfile
                    os.system(cmd)
                    if server_useXterm: cmd="xterm -e \"iperf -s -u -P 0 -i 1 -p %s -f k --reportstyle C | tee -a %s\" &"%(ulport,logfile)
                    else: cmd="iperf -s -u -P 0 -i 1 -p %s -f k --reportstyle C >> %s &"%(ulport,logfile)
                    #print(cmd);
                    os.system(cmd)
                    ueIperfserver_udp += 1
                if ulprotocol == "TCP":
                    print("Receiving %s traffic for %s (DRB%s) on port %s - from %s to %s" % (ulprotocol,ueid,drbid,ulport,ueip,cnip))
                    logfile="%s/data_logs/server/%s_iperf_UL_server_%s_DRB%s.csv"%(pwd,starttime,ueid,drbid)
                    cmd="touch %s"%logfile
                    os.system(cmd)
                    cmd="echo \"timestamp,src ip,src port,dest ip,dest port,Id,interval [sec],transfered [bytes],bandwidth [bps],jitter [ms],lost [pkt],total [pkt],lost [%%],out-of-order\" > %s"%logfile
                    os.system(cmd)
                    if server_useXterm: cmd="xterm -e \"iperf -s -w %s -i 5 -p %s --reportstyle C | tee -a %s\" &"%(ultcpws,ulport,ultcpws,logfile)
                    else: cmd="iperf -s -w %s -i 5 -p %s --reportstyle C >> %s &"%(ultcpws,ulport,logfile)
                    #print(cmd);
                    os.system(cmd)
                    ueIperfserver_tcp += 1
                else:
                    print("unknown '%s' protocol for iperf. Please use UL 'UDP' or 'TCP' protocol for %s (DRB%s)"%(ulprotocol,ueid,drbid))
        elif ulapp=='ping':
            if datagen_direction == 'UL_client':
                print("Sending ICMP traffic from %s to %s" % (ueip,cnip))
                logfile="%s/data_logs/client/%s_%s_DRB%s_ping_from_%s_to_%s.csv"%(pwd,starttime,ueid,drbid,ueip,cnip)
                cmd="ping %s -c %s > %s &" %(cnip,dltime,logfile)
                #print(cmd); 
                os.system(cmd)
                uePing += 1
            elif '_server' in datagen_direction:
                print("warning: ping can only be started with datagen_direction='UL_client'")
        else:
            print("sorry, the Data Generation Application '%s' is not supported. please use 'iperf' or 'ping' for %s (DRB%s)"%(ulapp,ueid,drbid)) 

        # DOWNLINK
        if dlapp=='iperf':
            # DL iperf CLIENT
            if datagen_direction == 'DL_client':
                if dlprotocol == "UDP":
                    print("Sending %s traffic for %s (DRB%s) on port %s - from %s to %s" % (dlprotocol,ueid,drbid,dlport,cnip,ueip))
                    logfile="%s/data_logs/client/%s_iperf_DL_client_%s_DRB%s.csv"%(pwd,starttime,ueid,drbid)
                    if client_useXterm: cmd="xterm -e \"iperf -c %s -u -P %s -i 1 -p %s -f k -l %s -b %s -t %s -T 1 | tee -a %s\" &" % (ueip,dlnumstreams,dlport,dlpktsize,dltput,dltime,logfile)
                    else: cmd="iperf -c %s -u -P %s -i 1 -p %s -f k -l %s -b %s -t %s -T 1 > %s &" % (ueip,dlnumstreams,dlport,dlpktsize,dltput,dltime,logfile)
                    #print(cmd); 
                    os.system(cmd)
                    cnIperfclient_udp += 1
                elif dlprotocol == "TCP":
                    print("Sending %s traffic for %s (DRB%s) on port %s - from %s to %s" % (dlprotocol,ueid,drbid,dlport,cnip,ueip))
                    logfile="%s/data_logs/client/%s_iperf_DL_client_%s_DRB%s.csv"%(pwd,starttime,ueid,drbid)
                    if client_useXterm: cmd="xterm -e \"iperf -c %s -w %s -P %s -i 1 -p %s -l %s -t %s | tee -a %s\" &" % (ueip,dltcpws,dlnumstreams,dlport,dlpktsize,dltime,logfile)
                    else: cmd="iperf -c %s -w %s -P %s -i 1 -p %s -l %s -t %s > %s &" % (ueip,dltcpws,dlnumstreams,dlport,dlpktsize,dltime,logfile)
                    #print(cmd); 
                    os.system(cmd)
                    cnIperfclient_tcp += 1
                else:
                    print("unknown '%s' protocol for iperf. Please use UL 'UDP' or 'TCP' protocol for %s (DRB%s)"%(dlprotocol,ueid,drbid))

            # DL iperf SERVER
            if datagen_direction == 'DL_server':
                if dlprotocol == "UDP":
                    print("Receiving %s traffic for %s (DRB%s) on port %s - from %s to %s" % (dlprotocol,ueid,drbid,dlport,cnip,ueip))
                    logfile="%s/data_logs/server/%s_iperf_DL_server_%s_DRB%s.csv"%(pwd,starttime,ueid,drbid)
                    cmd="touch %s"%logfile
                    os.system(cmd)
                    cmd="echo \"timestamp,src ip,src port,dest ip,dest port,Id,interval [sec],transfered [bytes],bandwidth [bps],jitter [ms],lost [pkt],total [pkt],lost [%%],out-of-order\" > %s"%logfile
                    os.system(cmd)
                    if server_useXterm: cmd="xterm -e \"iperf -s -u -P 0 -i 1 -p %s -f k --reportstyle C | tee -a %s\" &"%(dlport,logfile)
                    else: cmd="iperf -s -u -P 0 -i 1 -p %s -f k --reportstyle C >> %s &"%(dlport,logfile)
                    #print(cmd); 
                    os.system(cmd)
                    cnIperfserver_udp += 1
                elif dlprotocol == "TCP":
                    print("Receiving %s traffic for %s (DRB%s) on port %s - from %s to %s" % (dlprotocol,ueid,drbid,dlport,cnip,ueip))
                    logfile="%s/data_logs/server/%s_iperf_DL_server_%s_DRB%s.csv"%(pwd,starttime,ueid,drbid)
                    cmd="touch %s"%logfile
                    os.system(cmd)
                    cmd="echo \"timestamp,src ip,src port,dest ip,dest port,Id,interval [sec],transfered [bytes],bandwidth [bps],jitter [ms],lost [pkt],total [pkt],lost [%%],out-of-order\" > %s"%logfile
                    os.system(cmd)
                    if server_useXterm: cmd="xterm -e \"iperf -s -w %s -i 5 -p %s --reportstyle C | tee -a %s\" &"%(dltcpws,dlport,logfile)
                    else: cmd="iperf -s -w %s -i 5 -p %s --reportstyle C >> %s &"%(dltcpws,dlport,logfile)
                    #print(cmd); 
                    os.system(cmd)
                    cnIperfserver_tcp += 1
                else:
                    print("unknown '%s' protocol for iperf. Please use UL 'UDP' or 'TCP' protocol for %s (DRB%s)"%(dlprotocol,ueid,drbid))
        elif dlapp=='ping':
            if datagen_direction == 'DL_client':
                print("Sending ICMP traffic from %s to %s" % (cnip,ueip))
                logfile="%s/data_logs/client/%s_%s_DRB%s_ping_from_%s_to_%s.csv"%(pwd,starttime,ueid,drbid,cnip,ueip)
                cmd="ping %s -c %s > %s &" %(ueip,ultime,logfile)
                # #print(cmd); 
                os.system(cmd)
                cnPing += 1
            elif '_server' in datagen_direction:
                print("warning: ping can only be started with datagen_direction='DL_client'")
        else:
            print("sorry, the Data Generation Application '%s' is not supported. please use 'iperf' or 'ping' for %s (DRB%s)"%(dlapp,ueid,drbid)) 
        
        if ueTimeInterval != None: time.sleep(ueTimeInterval)

print "Data Generation Stats:"
print "  UL side [Pings: %s]\t[Iperf UDP Clients: %s]\t[Iperf UDP Servers: %s]\t[Iperf TCP Clients: %s]\t[Iperf TCP Servers: %s] " % (uePing,ueIperfclient_udp,ueIperfserver_udp,ueIperfclient_tcp,ueIperfserver_tcp)
print "  DL side [Pings: %s]\t[Iperf UDP Clients: %s]\t[Iperf UDP Servers: %s]\t[Iperf TCP Clients: %s]\t[Iperf TCP Servers: %s] " % (cnPing,cnIperfclient_udp,cnIperfserver_udp,cnIperfclient_tcp,cnIperfserver_tcp)
print "finsihed!"
inFile.close()
#eof